# Конвертер валют


### Как вообще работает этот код? 

Сначала создается структура для парсинга данных с json
в строку и другие типы для упрощения работы. В моём
случае она выглядит так:


```go
type CurrencyData struct {
	Valute map[string]struct {
		CharCode string  `json:"CharCode"`
		Value    float64 `json:"Value"`
	} `json:"Valute"`
}
```

По желанию можно структуру поменять, если Вы
собираетесь использовать для получения данных о
валютах другой сайт, или же вам нужно больше данных
по типу ID и т.д.

Сайт для справки:
```https://www.cbr-xml-daily.ru/daily_json.js```

Если вы решили парсить всю информацию о валютах с этого сайта, указанного в url, Ваша структура
может выглядеть примерно так:
```go
type CurrencyData struct {
    Valute map[string]struct {
        ID       string  `json:"ID"`
        NumCode  string  `json:"NumCode"`
        CharCode string  `json:"CharCode"`
        Nominal  int     `json:"Nominal"`
        Name     string  `json:"Name"`
        Value    float64 `json:"Value"`
        Previous float64 `json:"Previous"`
    } `json:"Valute"`
}
```


Дальше мы объявляем функцию, в которой делаем запрос
на получение данных из этого сайта. Для этого нужен
доступ в Интернет(логично), и доступ на сайт(В моем
случае он открытый):
```go
func getCurrencyRates() (map[string]float64, error) {
	// создается запрос на получение данных с урла
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
```

И вот, как только мы получили данные, читаем, если они есть:
```go
body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
```
Затем в действие приходит структура, которую мы создали ранее.

Объявляем её в коде и начинаем парсить json данные(если они пришли):
```go
var data CurrencyData
	err = json.Unmarshal(body, &data)
	if err != nil {
		return nil, err
	}
```

А затем, мы создаем карту, в которую помещаем данные о валюте:

```go
 rates := make(map[string]float64)
 ```
И, завершаем функцию выводом всех доступных(распарсенных) на данный момент валют:

```go
for key, valute := range data.Valute {
		rates[valute.CharCode] = valute.Value
		fmt.Printf("Валюта %s: %f\n", key, valute.Value)
	}
```

Есть вторая функция, основная, в которой проходят расчёты и т.д.

Сначала мы её объявляем, в аргументы передаем 2 объекта типа string и 1 типа float64, а сама функция имеет типы float64, error:
```go
func Convert(choose1, choose2 string, amount float64) (float64, error) {
	rates, err := getCurrencyRates()
	if err != nil {
		fmt.Println("Ошибка получения курса валют:", err)
	}
```
Также, в данном куске кода есть обращение к функции выше, а ещё происходит обращение, то есть
код дальше не пойдёт, если, например, данных нет или они не распарсились.


Затем мы запрашиваем у пользователя первую валюту,
если её ввели, к примеру, маленькими буквами(сама
валюта KZT, а ввели ее - kzT, то маленькие буквы
преобразятся в заглавные), ну а ещё проверка на 
существование валюты:
```go
fmt.Println("Выберите валюту для первого значения")
	fmt.Scanln(&choose1)
	// в случае если человек пишет маленьким регистром, то преобразуем к верхнему регистру
	choose1 = strings.ToUpper(choose1)
	_, exists1 := rates[choose1]
	// проверка на существование валюты
	if !exists1 {
		return 0, errors.New("Такой валюты не существует или выбрана неверная валюта")
	}
```
Подобный принцип и со второй валютой, но я добавил
проверку на одинаковые валюты:
```go
if rates[choose2] == rates[choose1] {
		return 0, errors.New("Вы ввели одинаковые валюты")
	}
```

Далее запрашивается количество первой валюты, и сама
формула вычисления:
```go
fmt.Println("Выберите количество", rates[choose1])
	fmt.Scanln(&amount)
	result := amount * rates[choose1] / rates[choose2]

	return result, nil
```

Выполнив тест, можно проверить, как работает код.